/* A wee progam to test the spangling sockets. */

/*#define _P __P*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <nd.h>
#include <sys/timeb.h>
#include "mptcpMgr.h"

#define SIOCLRP 0x8945

#define SOCKBUF 400000 //(64*1024)

#define RECV_LENGTH 8192 /*16348*/
#define MAX_CONNS   30

void *recver(void *arg);

unsigned int csum_partial(const unsigned char * buff, 
                          int len, unsigned int sum);

/*
 * Variables shared between all threads.
 */
int touch_data;
struct hostent *he;

char *eth = "eth0"; 
char *sourceIp; 
int my_port; 

extern struct net_device** ultcp_interface;
extern char ultcp_cnt;

int             sock;
int             num_conns = 0;
#ifdef USER_STACK
pthread_t       threads[30];
#endif
int                port;

long tvdif2us(struct timeval *t0, struct timeval *t1)
{
  struct timeval tdiff;
  long us;

  tdiff.tv_sec = t1->tv_sec - t0->tv_sec;
  tdiff.tv_usec = t1->tv_usec - t0->tv_usec;
  if (tdiff.tv_usec < 0)
    tdiff.tv_sec--, tdiff.tv_usec += 1000000;

  us = ((long)tdiff.tv_sec*1000000) + tdiff.tv_usec;
  return us;
}


int main(int argc, char *argv[])
{
    char               buf[2];
    int                i;
    int                ret;
    struct sockaddr_in laddr;

    /*
     * Initialise the stack as early as possible. It does some gross memory
     * mapping that is necessary for us not to crash!
     */

    /*
     * Parse the command line.
     */

    if((argc < 2))
    {
	fprintf(stderr, "%s: Usage: %s listen.ip advertised_interfaces\n", 
		argv[0], argv[0]);
	exit(EXIT_FAILURE);
    }

    port = strtol(argv[1], NULL, 10);
    if ( errno == ERANGE || port > 65535 || port < 0 )
    {
	fprintf(stderr, "%s: port \"%s\" invalid.\n", argv[0], argv[1]);
	exit(EXIT_FAILURE);
    }

    /*
     * Create and bind the listener.
     */

    printf("%s: listening on port %d.\n",   argv[0], port);
    laddr.sin_addr.s_addr = 0;
    laddr.sin_port        = htons(port);
    laddr.sin_family      = AF_INET;

    sock = mptcp_socket(AF_INET, SOCK_STREAM, 0, port);

    if ( sock < 0 ){
      fprintf(stderr, "Socket failed: %d (%s)\n",errno, strerror(errno));
      return(1);
    }


    ret = mptcp_bind(sock, 
		    (struct sockaddr *)&laddr, 
		    sizeof(struct sockaddr_in), argv, argc, 2);

    ret = mptcp_listen(sock, 5);
    if ( ret < 0 )
    {
	fprintf(stderr, "%s: listen failed: %d (%s)\n",
		argv[0], errno, strerror(errno));
	exit(EXIT_FAILURE);
    }

    /*
     * We accept() in each thread. After accepting, a thread spawns so that
     * connections can always be accepted.
     */
    recver(0);

    printf("close: \t\t");
    //    ret = mptcp_close(sock);
    printf("%d\n", ret);

    mptcp_kill();

    exit(EXIT_SUCCESS);
}


void *recver(void *arg)
{
  int                conn,i;
    struct sockaddr_in raddr;
    int                addrlen = sizeof(struct sockaddr_in);
    int                fd[10];
    int                old_totals, totals, calls;
    struct timeval     old_time, curr_time;
    int                received, ret;
    char               buf[RECV_LENGTH];
    fd_set readfds;
    struct timeval tv1;
    int max_fd;
    int total_recv[10];
    int cnt = 0,j;
    unsigned int start;
    unsigned int last_print;
    int read_print;
    struct timeb tb;
    conn = -1;

    /*
     * Accept a connection.
     */

    for (i=0;i<10;i++)
      total_recv[i] = 0;

    printf("Waiting for accept...\n");

    cnt = 0;
    while (1){
      my_upcall_worker(NULL);

      FD_ZERO(&readfds);
      FD_SET(sock,&readfds);
      max_fd = sock;

      for (i=0;i<=conn;i++){
	FD_SET(fd[i],&readfds);

	if (fd[i]>max_fd)
	  max_fd = fd[i];
      }

      tv1.tv_sec = 0;
      tv1.tv_usec = 0;

      mptcp_select(max_fd+1,&readfds, NULL, NULL, &tv1); 

      if (FD_ISSET(sock,&readfds)){
	//	if (conn==1)
	  {fd[++conn] = mptcp_accept(sock, (struct sockaddr *)&raddr, &addrlen);
	    printf("Accept sock %d on connection %d\n",fd[conn],conn);
	    ftime(&tb);
	    start = tb.time*1000+tb.millitm;
	    read_print = 0;
	    last_print = start;
	    if (fd[conn]<0){
	      fprintf(stderr, "Accept failed: %d (%s)\n", errno, strerror(errno));
	      exit(1);
	    }
	    mptcp_fcntl(fd[conn]); 
	  }
      }

      for (i=0;i<=conn;i++)
	if (FD_ISSET(fd[i],&readfds)){
	  do {
	    received = mptcp_recv(fd[i], buf, RECV_LENGTH, MSG_DONTWAIT);
	    if ( received < 0 ){
	      if (errno == EWOULDBLOCK){
	      //printf("Got EWOULDBLOCK in conn %d after transferring %d bytes...", received);
	      //fflush(stdout);
		break;
	      }
	      else {
		fprintf(stderr, "Read failed: %d (%s)\n", errno, strerror(errno));
		exit(1);
	      }
	    }
	    //do checksum!
	    /*	    for (j=0;j<received;j++){
	      if (buf[j]!=(char)(cnt%14000)){
		int min = 0,max = received;
		printf("Checksum error at byte %d, pos %d\n",cnt,j);
		if (min<j-10)
		  min = j-10;
		if (max>j+10)
		  max = j+10;
		for (j=min;j<max;j++)
		  printf("%d ",buf[j]);
		exit(1);
	      }
	      cnt = (cnt+1);
	      }*/
	  

	    else {
	    printf("%s", buf); 
	      break; 
	      total_recv[i] += received;
	 }
	  }while (1);
	}
    }
} 

/* End of $RCSFile$ */
